#include <linux/module.h>
#include <linux/kthread.h>
#include <linux/wait.h>

static struct task_struct * slam1, * slam2;

static wait_queue_head_t slam_wq_head;
static wait_queue_t slam_wq;

static int wakeup_condition = 0;

extern unsigned long msleep_interruptible(unsigned int msecs);

static int slam_wq_func(wait_queue_t *wait, unsigned mode, int flags, void *key)
{
	printk("I'm in slam_wq_func!\n");
	return 0;
}

static int slam1_func(void *data)
{
	do{
		printk("I'm in slam1,wating slam_wq_head to wakeup me!\n");
		wait_event_interruptible(slam_wq_head, wakeup_condition == 5);
		wakeup_condition=0;
		printk("slam1:slam_wq_head wakeup me done!\n");
	}while(!kthread_should_stop());

	return 0;
}

static int slam2_func(void *data)
{
	do{
		printk("I'm in slam2_func,i'll do wakeup!\n");
		wakeup_condition++;
		if((wakeup_condition == 5) && waitqueue_active(&slam_wq_head)){
			wake_up_interruptible(&slam_wq_head);
		}
		msleep_interruptible(1000);		
	}while(!kthread_should_stop());

	return 0;
}

static __init int kthread_waitqueue_init(void)
{
	init_waitqueue_head(&slam_wq_head);
	init_waitqueue_func_entry(&slam_wq, slam_wq_func);
	add_wait_queue(&slam_wq_head, &slam_wq);

	slam1 = kthread_run(slam1_func, NULL, "slam1");
	if(IS_ERR(slam1))
	{
		printk("kthread_run slam1 failed!\n");
		return 1;
	}

	slam2 = kthread_run(slam2_func, NULL, "slam2");
	if(IS_ERR(slam2))
	{
		printk("kthread_run slam2 failed!\n");
		return 1;
	}

	return 0;
}

static __exit void kthread_waitqueue_exit(void)
{
	if(!IS_ERR(slam1))
	      kthread_stop(slam1);

	if(!IS_ERR(slam2))
	      kthread_stop(slam2);
}

module_init(kthread_waitqueue_init);
module_exit(kthread_waitqueue_exit);
